package db

import (
	"fmt"
	"strings"
	"time"

	"github.com/jmoiron/sqlx"
	_ "github.com/mattn/go-sqlite3"
)

/* ==================  用户可改的全局配置  ================== */

var (
	SQLiteDriver = "sqlite3" // 或 "sqlite3"

	// 连接池（SQLite 单连接即可，>1 反而容易锁）
	MaxOpenConns    = 1                // 同时打开的最大连接数；SQLite 写独占，1 足矣
	MaxIdleConns    = 1                // 最大空闲连接数，保持 1 条复用即可
	ConnMaxLifetime = time.Duration(0) // 连接永不过期（0 表示无限制）
	ConnMaxIdleTime = 10 * time.Second // 空闲超过 10 秒自动关闭

	// 单行 PRAGMA，分号分隔，一次性执行
	InitPragmas = strings.Join([]string{
		"PRAGMA foreign_keys = ON",    // 启用外键约束；破坏外键时立即报错
		"PRAGMA busy_timeout = 5000",  // 表被锁时最多等待 5 秒，防止 "database is locked"
		"PRAGMA journal_mode = WAL",   // WAL 模式，读写并发性能更好
		"PRAGMA synchronous = NORMAL", // 折中刷盘策略：安全+高吞吐
	}, "; ")

	// 建库时才会执行的初始化 SQL（建表、写初始数据等）
	// 留空则什么都不做
	InitSQL = `
	CREATE TABLE IF NOT EXISTS users (
		id INTEGER PRIMARY KEY AUTOINCREMENT,
		username TEXT NOT NULL UNIQUE,
		password TEXT NOT NULL,
		created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
	);
	-- 插入管理账号
	INSERT INTO users (username, password) VALUES ("admin", "admin");
	`
)

/* ========================================================= */

// NewDB 连接 SQLite，仅在库文件首次创建时执行 InitSQL
//
// 参数：
//   - dataSource: 数据库文件路径，如 ":memory:" 表示内存数据库
//
// 返回值：
//   - *sqlx.DB: 数据库连接实例
//   - error: 连接或初始化过程中的错误
func NewDB(dataSource string) (*sqlx.DB, error) {
	db, err := sqlx.Connect(SQLiteDriver, dataSource)
	if err != nil {
		return nil, fmt.Errorf("connect sqlite: %w", err)
	}

	// 连接池
	db.SetMaxOpenConns(MaxOpenConns)
	db.SetMaxIdleConns(MaxIdleConns)
	db.SetConnMaxLifetime(ConnMaxLifetime)
	db.SetConnMaxIdleTime(ConnMaxIdleTime)

	// 统一 PRAGMA
	if _, err := db.Exec(InitPragmas); err != nil {
		_ = db.Close()
		return nil, fmt.Errorf("exec pragmas: %w", err)
	}

	// 判断是否需要执行 InitSQL
	var uv int
	if err := db.Get(&uv, "PRAGMA user_version"); err != nil {
		_ = db.Close()
		return nil, fmt.Errorf("get user_version: %w", err)
	}

	// user_version == 0 表示刚创建的库
	if uv == 0 && strings.TrimSpace(InitSQL) != "" {
		// 执行初始化 SQL
		if _, err := db.Exec(InitSQL); err != nil {
			_ = db.Close()
			return nil, fmt.Errorf("exec init sql: %w", err)
		}

		// 标记为已初始化
		if _, err := db.Exec("PRAGMA user_version = 1"); err != nil {
			_ = db.Close()
			return nil, fmt.Errorf("set user_version: %w", err)
		}
	}

	return db, nil
}
